package com.flame.workflow.ru.engine.handler;

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.core.type.TypeReference;
import com.flame.auth.core.entity.TrustedPrincipal;
import com.flame.core.utils.DateUtils;
import com.flame.workflow.constants.RuntimeConstants;
import com.flame.workflow.constants.TaskConstants;
import com.flame.workflow.constants.UserTaskConstants;
import com.flame.workflow.id.entity.WorkflowUser;
import com.flame.workflow.id.service.IdentityService;
import com.flame.workflow.ru.engine.context.RuntimeContext;
import com.flame.workflow.ru.entity.Instance;
import com.flame.workflow.ru.entity.Task;
import com.flame.workflow.ru.entity.TaskComment;
import com.flame.workflow.ru.entity.UserTask;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;
import org.springframework.util.ObjectUtils;

import java.util.*;

/**
 * @author wuxintong😺😺😺
 * @since 2023/6/6
 */
@Service("workflow-approval-task-handler")
public class ApprovalTaskHandler extends AbstractTaskHandler {

    private static final String APPROVE = "1";

    private static final String REFUSE = "0";

    @Autowired
    private IdentityService identityService;

    @Override
    public Task startTask(RuntimeContext runtimeContext) {
        Task task = super.startTask(runtimeContext);
        createUserTask(runtimeContext.getInstance(), task);
        return task;
    }

    @Override
    public String runTask(RuntimeContext runtimeContext) {
        Instance instance = runtimeContext.getInstance();
        Task task = runtimeContext.getTask();
        if (RuntimeConstants.RUNTIME_STATUS_WAIT.equals(task.getTaskStatus())) {
            TrustedPrincipal principal = runtimeContext.getTrustedPrincipal();
            Map<String, String> taskProperties = task.getTaskProperties();
            String approveResult =
                    taskProperties.getOrDefault(TaskConstants.TASK_APPROVE_RESULT + principal.getAccount(), "0");
            String approveMessage = taskProperties.get(TaskConstants.TASK_APPROVE_MESSAGE + principal.getAccount());

            TaskComment taskComment = new TaskComment();
            taskComment.setCommentId(idWorker.nextId());
            taskComment.setInstanceId(instance.getInstanceId());
            taskComment.setTaskId(task.getTaskId());
            taskComment.setUserId(principal.getAccount());
            taskComment.setMessage(approveMessage);
            taskComment.setCreateTime(DateUtils.currentDateTime());
            taskCommentMapper.insert(taskComment);

            String approvalType = taskProperties.getOrDefault(TaskConstants.MULTI_APPROVAL_TYPE, "0");
            // 或签 - 有 1 人同意，即通过
            if (TaskConstants.MULTI_APPROVAL_TYPE_OR_SIGN.equals(approvalType)) {
                if (APPROVE.equals(approveResult)) {
                    userTaskService.completeByTaskIdAndUserId(task.getTaskId(), principal.getAccount(),
                            UserTaskConstants.USER_TASK_STATUS_COMPLETE_SUCCESS, true);
                    return RuntimeConstants.RUNTIME_STATUS_COMPLETE;
                }
                if (REFUSE.equals(approveResult)) {
                    userTaskService.completeByTaskIdAndUserId(task.getTaskId(), principal.getAccount(),
                            UserTaskConstants.USER_TASK_STATUS_COMPLETE_ERROR, false);
                    List<UserTask> userTaskList = userTaskService.listCreateUserTask(task.getTaskId());
                    if (CollectionUtils.isEmpty(userTaskList)) {
                        return RuntimeConstants.RUNTIME_STATUS_ERROR;
                    }
                    return RuntimeConstants.RUNTIME_STATUS_WAIT;
                }
            }
            // 会签 - 所有人同意，即通过
            if (TaskConstants.MULTI_APPROVAL_TYPE_ALL_SIGN.equals(approvalType)) {
                if (REFUSE.equals(approveResult)) {
                    userTaskService.completeByTaskIdAndUserId(task.getTaskId(), principal.getAccount(),
                            UserTaskConstants.USER_TASK_STATUS_COMPLETE_ERROR, true);
                    return RuntimeConstants.RUNTIME_STATUS_ERROR;
                }
                if (APPROVE.equals(approveResult)) {
                    userTaskService.completeByTaskIdAndUserId(task.getTaskId(), principal.getAccount(),
                            UserTaskConstants.USER_TASK_STATUS_COMPLETE_SUCCESS, false);
                    List<UserTask> userTaskList = userTaskService.listCreateUserTask(task.getTaskId());
                    if (CollectionUtils.isEmpty(userTaskList)) {
                        return RuntimeConstants.RUNTIME_STATUS_COMPLETE;
                    }
                    return RuntimeConstants.RUNTIME_STATUS_WAIT;
                }
            }
        }
        return RuntimeConstants.RUNTIME_STATUS_WAIT;
    }

    @Override
    public boolean handleError(RuntimeContext runtimeContext) {
        Instance instance = runtimeContext.getInstance();
        Task task = runtimeContext.getTask();
        Map<String, String> taskProperties = task.getTaskProperties();
        // 审批拒绝方式：驳回至上级节点
        if (TaskConstants.APPROVAL_REFUSED_TYPE_RETURN_UP_NODE
                .equals(taskProperties.get(TaskConstants.APPROVAL_REFUSED_TYPE))) {
            // 查看上级节点是否为审批、开始节点，若不是，直接结束
            Task parentTask = taskService.getTask(task.getParentTaskId());
            if (TaskConstants.TASK_TYPE_START.equals(parentTask.getTaskType()) ||
                    TaskConstants.TASK_TYPE_APPROVAL.equals(parentTask.getTaskType())) {
                // 把当前任务删除
                taskService.deleteTask(task.getTaskId());
                // 删除上级节点任务，并重新创建
                taskService.deleteTask(parentTask.getTaskId());
                parentTask.setTaskId(idWorker.nextId());
                parentTask.setTaskStatus(RuntimeConstants.RUNTIME_STATUS_WAIT);
                taskService.addTask(parentTask);
                Map<String, String> nodeProperties = nodeService
                        .getNodeProperties(instance.getModelId(), instance.getModelVersion(), parentTask.getNodeId());
                taskPropertyService.addTaskProperty(instance.getInstanceId(), parentTask.getTaskId(), nodeProperties);
                // 添加用户任务
                createUserTask(instance, parentTask);
                return false;
            }
            return true;
        }
        // 审批拒绝方式：驳回至指定节点
        if (TaskConstants.APPROVAL_REFUSED_TYPE_RETURN_SPECIFIC_NODE
                .equals(taskProperties.get(TaskConstants.APPROVAL_REFUSED_TYPE))) {
            // 检查指定节点，是否为当前节点，或当前节点的下级节点，若是，直接结束
            Integer specificNodeId = Integer.parseInt(taskProperties.get(TaskConstants.APPROVAL_REFUSED_TO_NODE_ID));
            if (task.getNodeId().equals(specificNodeId)) {
                return true;
            }
            if (isChildNode(task, specificNodeId)) {
                return true;
            }
            // 获得指定节点任务
            Task specificTask = taskService.getTaskByNodeId(instance.getInstanceId(), specificNodeId);
            // 删除指定节点的下级任务
            List<Task> waitDeleteTaskList = new ArrayList<>();
            waitDeleteTaskList.add(specificTask);
            deleteChildTask(specificTask);
            // 删除指定节点任务，并重新创建
            taskService.deleteTask(specificTask.getTaskId());
            specificTask.setTaskId(idWorker.nextId());
            specificTask.setTaskStatus(RuntimeConstants.RUNTIME_STATUS_WAIT);
            taskService.addTask(specificTask);
            Map<String, String> nodeProperties = nodeService
                    .getNodeProperties(instance.getModelId(), instance.getModelVersion(), specificTask.getNodeId());
            taskPropertyService.addTaskProperty(instance.getInstanceId(), specificTask.getTaskId(), nodeProperties);
            // 添加用户任务
            createUserTask(instance, specificTask);
            return false;
        }
        // 审批拒绝方式：直接结束流程
        if (TaskConstants.APPROVAL_REFUSED_TYPE_FINISH
                .equals(taskProperties.get(TaskConstants.APPROVAL_REFUSED_TYPE))) {
            return true;
        }
        return true;
    }

    private void deleteChildTask(Task specificTask) {
        List<Task> taskList = taskService.listByParentTaskId(specificTask.getTaskId());
        if (CollectionUtils.isEmpty(taskList)) {
            return;
        }
        for (Task task : taskList) {
            taskService.deleteTask(task.getTaskId());
            deleteChildTask(task);
        }
    }

    private boolean isChildNode(Task task, Integer nodeId) {
        if (ObjectUtils.isEmpty(task)) {
            return false;
        }
        if (task.getNodeId().equals(nodeId)) {
            return true;
        }
        List<Task> childTaskList = taskService.listByParentTaskId(task.getTaskId());
        for (Task childTask : childTaskList) {
            boolean res = isChildNode(childTask, nodeId);
            if (res) {
                return true;
            }
        }
        return false;
    }

    private void createUserTask(Instance instance, Task task) {
        if (TaskConstants.TASK_TYPE_START.equals(task.getTaskType())) {
            userTaskService.addUserTask(instance.getInstanceId(), task.getTaskId(), instance.getUserId());
            return;
        }
        Map<String, String> taskProperties = task.getTaskProperties();
        String approvalType = taskProperties.get("approvalType");
        String approvalListJson = taskProperties.get("approvalList");
        try {
            List<String> approvalList = objectMapper.readValue(approvalListJson, new TypeReference<List<String>>() {
            });
            if (UserTaskConstants.USER_TASK_TYPE_USER.equals(approvalType)) {
                for (String userId : approvalList) {
                    userTaskService.addUserTask(instance.getInstanceId(), task.getTaskId(), userId);
                }
            }
            if (UserTaskConstants.USER_TASK_TYPE_ROLE.equals(approvalType)) {
                Set<String> userIdSet = new HashSet<>();
                for (String roleCode : approvalList) {
                    Set<String> userIdList = identityService.listWorkflowUserIdByRoleCode(roleCode);
                    for (String userId : userIdList) {
                        if (userIdSet.contains(userId)) {
                            continue;
                        }
                        userTaskService.addUserTask(instance.getInstanceId(), task.getTaskId(), userId);
                    }
                    userIdSet.addAll(userIdList);
                }
            }
            if (UserTaskConstants.USER_TASK_TYPE_DEPT.equals(approvalType)) {
                for (String orgCode : approvalList) {
                    List<WorkflowUser> userInfoList = identityService.listWorkflowUserByOrgCode(orgCode);
                    for (WorkflowUser userInfo : userInfoList) {
                        userTaskService.addUserTask(instance.getInstanceId(), task.getTaskId(), userInfo.getUserId());
                    }
                }
            }
        } catch (JsonProcessingException e) {
            e.printStackTrace();
        }
    }

    @Override
    public String taskType() {
        return TaskConstants.TASK_TYPE_APPROVAL;
    }
}
